/*
 * This source code is part of TWaver 4.0
 *
 * Serva Software PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * Copyright 2002 - 2011 Serva Software. All rights reserved.
 */

package demo.tree.file;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileSystemView;

import twaver.DataBoxSelectionAdapter;
import twaver.DataBoxSelectionEvent;
import twaver.Element;
import twaver.Generator;
import twaver.TDataBox;
import twaver.TWaverUtil;
import twaver.VisibleFilter;
import twaver.tree.LazyLoader;
import twaver.tree.TTree;
import twaver.tree.TTreeCellIcon;
import demo.DemoPane;
import demo.DemoUtil;

public class FileTreeDemo extends DemoPane{
	
	protected DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
	protected FileSystemView fileSystemView = FileSystemView.getFileSystemView();
	protected TDataBox box = new TDataBox("File System Demo");
	protected JTextArea trace = DemoUtil.createColorTextArea();
	
	protected JLabel fileInfo = new JLabel(" ");
	protected JCheckBox displayFileNode;
	protected JCheckBox displaySystemIcon;
	protected JCheckBox precheckChildren;
	
	private String loadingIcon = "/demo/tree/file/loading.gif";
	private int counter = 0;
	
	protected TTree tree = new TTree(box){
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if(counter > 0){
            	paintMirage((Graphics2D)g);
            }
        }
	};
	
	private void increaseCounter(){
		counter++;
		tree.repaint();
	}
	
	private void decreaseCounter(){
		counter--;
		tree.repaint();
	}
	
	private void paintMirage(Graphics2D g){
		g.setColor(new Color(255, 255, 255, 128));
		g.fill(tree.getVisibleRect());
	}
	
	// before element is added to box, it will not influence 
	// network,tree,table,etc. which connected with the box.
	// so here we do not need to care about swing thread safety.
	private FileElement createElement(File file){ 
		FileElement element = new FileElement(file);		
		// determine leaf
		if(precheckChildren.isSelected()){
			if(file.isDirectory()){
				File[] files = fileSystemView.getFiles(file, false);
				if (files != null && files.length > 0) {
					element.setLoaded(false);
					element.setLeaf(false);
				}else{
					element.setLoaded(true);
					element.setLeaf(true);
				}
			}else{
				element.setLoaded(true);
				element.setLeaf(true);
			}
		}

		// determine label and icon
		element.setName(fileSystemView.getSystemDisplayName(file));
		Icon icon = fileSystemView.getSystemIcon(file);
		element.putElementTreeIcon(icon);
		
		// "JTextArea.append" method is thread safe, 
		// although most Swing methods are not.
		trace.append("loading >> " + element.getName());
		
		return element;
	}
	
	public void loadChildren(final FileElement element) {
		final String oldIconURL = element.getIconURL();
		element.setIcon(loadingIcon);
		
		Thread t = new Thread(new Runnable(){
			public void run() {
				
				// fileSystemView.getFiles may cost a lot of time,
				// so we create all element in NOT swing thead.
				File file = element.getFile();
				File[] files = fileSystemView.getFiles(file, true);
				final List children = new ArrayList();
				if (files != null && files.length > 0) {					
					for (int i = 0; i < files.length; ++i) {
						children.add(createElement(files[i]));
					}
				}
				
				// when you want to add element to the box that
				// already connected with swing component like tree,
				// network, table, sheet, etc. you should do this 
				// job in swing thread.
				SwingUtilities.invokeLater(new Runnable(){
					public void run() {
						box.addElements(children, element);
						element.setLoaded(true);
						element.setIcon(oldIconURL);
						decreaseCounter();
					}
				});
			}
		});
		
		increaseCounter();
		t.start();
	}
	
	public FileTreeDemo(){
		fileInfo.setOpaque(true);
		fileInfo.setBackground(Color.BLACK);
		fileInfo.setForeground(Color.GREEN);
		
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(createFilterPanel(), BorderLayout.NORTH);
		JScrollPane sp = new JScrollPane(tree);
		panel.add(sp, BorderLayout.CENTER);
		
		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panel, new JScrollPane(trace));
		split.setDividerLocation(250);
		this.add(split, BorderLayout.CENTER);
		this.add(fileInfo, BorderLayout.SOUTH);

		// load first layer elements
		File[] files = fileSystemView.getRoots();
		for(int i=0; i<files.length; i++){
			FileElement element = createElement(files[i]);
			box.addElement(element);
		}
		tree.setRootVisible(false);
				
		// lazyloader
		tree.setLazyLoader(new LazyLoader(){
			public void load(final Element element) {
				FileElement fileElement = (FileElement)element;
				loadChildren(fileElement);
			}
			public boolean isLoaded(Element element) {
				FileElement fileElement = (FileElement)element;
				return fileElement.isLoaded();
			}
			public boolean isLeaf(Element element) {
				if(precheckChildren.isSelected()){
					FileElement fileElement = (FileElement)element;
					return fileElement.isLeaf();
				}else{
					return false;
				}
			}
		});
		
		
		// selection change process
		box.getSelectionModel().addDataBoxSelectionListener(new DataBoxSelectionAdapter(){
			public void selectionChanged(DataBoxSelectionEvent e) {
				if(box.getSelectionModel().size() == 1){
					FileElement element = (FileElement)box.getLastSelectedElement();
					File file = element.getFile();
					Date date = new Date(file.lastModified());
					fileInfo.setText(
							" " + file.getAbsolutePath() + 
							" " + fileSystemView.getSystemTypeDescription(file) + 
							" " + dateFormat.format(date));
				}
			}
		});
		
		tree.setEnableAnimation(true);
		tree.setElementIconGenerator(new Generator() {
            public Object generate(Object object) {
            	return new TTreeCellIcon(((Element)object), tree){
            		protected Icon getElementIcon() {
            			if(element.getIconURL() == loadingIcon){
            				return TWaverUtil.getImageIcon(loadingIcon);
            			}
            			FileElement fileElement = (FileElement)element;
            			if(displaySystemIcon.isSelected()){
            				return fileElement.getElementTreeIcon();
            			}
            			String url;
                        if(fileElement.getFile().isDirectory()){
                        	if(tree.isExpanded(element)){
                        		url = "/demo/tree/file/openIcon.gif";
                        	}else{
                        		url = "/demo/tree/file/closedIcon.gif";
                        	}
                        }else{
                        	url = "/demo/tree/file/leafIcon.gif";
                        }
                        return TWaverUtil.getImageIcon(url);
            		}
            	};
            }
        });
		
	}
	
	private JPanel createFilterPanel(){
		JPanel panel = new JPanel(new GridLayout(3, 1));
		this.displayFileNode = new JCheckBox("Display File Node", true);
		this.displaySystemIcon = new JCheckBox("Display System Icon", true);
		this.precheckChildren = new JCheckBox("Precheck Children", true); 
		panel.add(this.displaySystemIcon);
		panel.add(this.displayFileNode);
		panel.add(this.precheckChildren);
		
		this.displayFileNode.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				tree.updateTViewUI();
				tree.expandRow(0);
			}
		});
		this.displaySystemIcon.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				tree.repaint();
			}
		});
		this.tree.addVisibleFilter(new VisibleFilter(){
			public boolean isVisible(Element element) {
				FileElement fileElement = (FileElement)element;
				File file = fileElement.getFile();
				if(!displayFileNode.isSelected() && !file.isDirectory()){
					return false;
				}
				return true;
			}
		});
		
		return panel;
	}

}